#include "my_sem.h"

/*
问：是否熟悉 IPC机制中的信号灯集合 用过哪些功能 他的优势
答：熟悉 精通
    二值信号灯 用于管理进程间同步互斥的问题
    优势 可以分多组管理进程

    还用过IPC机制来进行顺序控制

线程的创建  概念
    如果在线程中创建线程
        在线程中没有子线程 或 孙线程的概念
进程的创建  概念

同步互斥的概念
    线程
        互斥锁
        信号量
        条件变量
    进程
        信号灯集
通讯
    线程
        全局
    进程
        管道 有名管道 无名管道
            无名管道  内核 不能再非关系的进程下
            有名管道  文件
        信号

        消息队列

        共享内存
            传输速度最快

        套接字

        文件

*/
// 初始化
int Sem_init(int num)
{
    // 声明描述符
    int semid;

    key_t key = ftok("./key", 'A');

    union semun set_val;

    // 创建信号灯集
    if ((semid = semget(key, num, IPC_CREAT | IPC_EXCL | 0666)) == -1)
    {
        if (errno == EEXIST)
        {
            // 如果已经存在 ， 就直接返回

            semid = semget(key, num, IPC_CREAT | 0666);

            printf("信号灯集创建成功 id = %d \n", semid);

            return semid;
        }
        else
        {
            perror("semget error");
            return -1;
        }
    }

    // 初始化信号灯的值   编号 0  ->  1
    for (int i = 0; i < num; i++)
    {

        set_val.val = (i == 0) ? 1 : 0;
        printf("111设定信号灯状态 %d \n", set_val.val);
        if (semctl(semid, i, SETVAL, set_val) == -1)
        {
            perror("semctl error");
            return -1;
        }
    }

    printf("信号灯集创建成功 id = %d \n", semid);

    return semid;
}

// P 操作semid  信号灯集的id  sem_num 信号灯的id
void sem_P(int semid, int sem_num)
{
    // 设定结构体
    struct sembuf sem_buf = {
        .sem_num = sem_num,
        .sem_op = -1,
        .sem_flg = 0};

    // 将结构体写入 semop 函数中
    if (semop(semid, &sem_buf, 1) == -1)
    {
        perror("P操作错误\n");
        return;
    }
}

// V 操作
void sem_V(int semid, int sem_num)
{
    // 设定结构体
    struct sembuf sem_buf = {
        .sem_num = sem_num,
        .sem_op = 1,
        .sem_flg = 0};

    // 将结构体写入 semop 函数中
    if (semop(semid, &sem_buf, 1) == -1)
    {
        perror("V操作错误\n");
        return;
    }
}
